package bev;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.*;
import java.util.Properties;

public class ConnectionManager {

    static final String DRIVER = "com.mysql.jdbc.Driver";
    static String DATABASE_URL;
    static String DATABASE_USER;
    static String DATABASE_PASS;
    static Connection con = null;
    static boolean connected;
    static AppManager appManager = null;

    public static boolean isConnected() {
        return connected;
    }

    // Sets a reference to the AppManager running the application.
    public static void setAppManager( AppManager appManager ) {
        ConnectionManager.appManager = appManager;
    }

    public static void setDatabaseInfo( String url, String user, String pass ) {
        // Protects code from breaking on '0000-00-00 00:00:00' timestamps.
        DATABASE_URL = String.format( "%s?zeroDateTimeBehavior=convertToNull",
                url );
        DATABASE_USER = user;
        DATABASE_PASS = pass;

        // Inform the AppManager of the new database
        // connection if an AppManager reference has been set.
        if ( appManager != null ) {
            appManager.onConnectionSet();
        }

        connected = true;
    }

    public static void closeConnection() {
        try {
            con.close();
        } catch ( SQLException ex ) {

        }
    }

    public static boolean testDatabaseConnection( String url, String user,
            String pass ) {
        // Create connection storage;
        Connection con = null;
        try {
            Class.forName( DRIVER );
            // Manage properties of connection
            Properties props = new Properties();
            props.put( "user", user );
            props.put( "password", pass );
            // Create actual connection
            con = DriverManager.getConnection( url, props );

            con.close();
        } catch ( SQLException ex ) {
            ex.printStackTrace();
            return false;
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
            return false;
        }

        return true;

    }

    public static ResultSet RunSQLQuery( String sqlquery ) throws SQLException,
            ClassNotFoundException {
        // Create connection storage;
        try {
            Class.forName( DRIVER );
            // Manage properties of connection
            Properties props = new Properties();
            props.put( "user", DATABASE_USER );
            props.put( "password", DATABASE_PASS );
            // Create actual connection
            con = DriverManager.getConnection( DATABASE_URL, props );

        } catch ( SQLException ex ) {
            ex.printStackTrace();
            return null;
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
            return null;
        }

        Statement statement = con.createStatement();
        ResultSet results = statement.executeQuery( sqlquery );

        return results;
    }

    public static int RunSQLUpdateQuery( String sqlquery ) throws SQLException,
            ClassNotFoundException {
        // Create connection storage;
        try {
            Class.forName( DRIVER );
            // Manage properties of connection
            Properties props = new Properties();
            props.put( "user", DATABASE_USER );
            props.put( "password", DATABASE_PASS );
            // Create actual connection
            con = DriverManager.getConnection( DATABASE_URL, props );

        } catch ( SQLException ex ) {
            ex.printStackTrace();
            return -1;
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
            return -1;
        }

        Statement statement = con.createStatement();
        int results = statement.executeUpdate( sqlquery );

        return results;
    }

    /**
     * Takes in a string and applies escape sequencing for mySQL characters.
     */
    public static String processEscapeChars( String input ) {
        String output = "";
        char[] mysqlChars = { '\'', '\"', '\\', '%', '_' };
        for ( char c : input.toCharArray() ) {
            // Add '\' for mysql characters.
            for ( char sqlChar : mysqlChars ) {
                if ( c == sqlChar ) {
                    output = String.format( "%s\\", output );
                    break;
                }
            }

            // Place the character in the output String.
            output = String.format( "%s%c", output, c );
        }

        return output;
    }

    /**
     * Writes the current connection data used by the ConnectionManager class to
     * a file.
     * 
     * @param filePath
     *            The file to write the connection data to.
     */
    public static Boolean writeConnectionFile( String filePath ) {
        ConnectionFileData fd = new ConnectionFileData( DATABASE_URL,
                DATABASE_USER, DATABASE_PASS );

        try {
            FileOutputStream fileStream = new FileOutputStream( filePath );
            ObjectOutputStream outStream = new ObjectOutputStream( fileStream );
            outStream.writeObject( fd );
            outStream.close();
            fileStream.close();

            return true;
        } catch ( FileNotFoundException ex ) {
            System.err.printf( "ERROR: File not found: %s\n", filePath );
            ex.printStackTrace();
        } catch ( IOException ex ) {
            ex.printStackTrace();
        }

        return false;
    }

    /**
     * Reads in connection data from a file and set the ConnectionManager class
     * to use that data.
     * 
     * @param filePath
     *            The file to read the connection data from.
     */
    public static Boolean readConnectionFile( String filePath ) {
        try {
            FileInputStream fileStream = new FileInputStream( filePath );
            ObjectInputStream inStream = new ObjectInputStream( fileStream );
            ConnectionFileData fd = (ConnectionFileData) inStream.readObject();
            inStream.close();
            fileStream.close();

            if ( testDatabaseConnection( fd.getURL(), fd.getUser(),
                    fd.getPassword() ) ) {
                // Protects code from breaking on '0000-00-00 00:00:00'
                // timestamps.
                DATABASE_URL = fd.getURL();
                DATABASE_USER = fd.getUser();
                DATABASE_PASS = fd.getPassword();

                // Inform the AppManager of the new database
                // connection if an AppManager reference has been set.
                if ( appManager != null ) {
                    appManager.onConnectionSet();
                }

                connected = true;

                return true;
            }
        } catch ( FileNotFoundException ex ) {
            System.err.printf( "ERROR: File not found: %s", filePath );
            ex.printStackTrace();
        } catch ( IOException ex ) {
            ex.printStackTrace();
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
        }

        return false;
    }
}
